<!-- 菜单弹框 - 新增、查看、修改 -->
<template>
    <el-dialog 
        :title="typeTitle + '菜单'"
        v-model="dialogVisible"
        width="45%"
        :close-on-click-modal="false" 
        :close-on-press-escape="true"
        @closed="resetForm(formRef)">
        <el-form :model="form" ref="formRef" :rules="rules" label-width="100px">
            <el-form-item label="上级菜单" prop="parentId">
                <div class="top-menus-box" tabindex="0">
                    <input type="text" v-model.number="parentTitle" @click="onMenuclick" :readonly="billState">
                    <!-- 上级菜单 -->
                    <div class="menus-tree-container" v-show="menusVisible">
                        <el-row class="icon-box" justify="end">
                            <el-icon :size="16" @click="onMenuclick">
                                <Close />
                            </el-icon>
                        </el-row>
                        <MenusTree 
                        :treeData="menuList" 
                        :showCheckbox="false" 
                        :onClickNode="false" 
                        @nodeClick="nodeClick"
                        :filterKey="parentTitle"/>
                    </div>
                </div>
            </el-form-item>
            <el-form-item label="菜单类型" prop="">
                <el-radio-group v-model="form.type" :disabled="billState">
                    <el-radio :value="1">目录</el-radio>
                    <el-radio :value="2">菜单</el-radio>
                    <el-radio :value="3">按钮</el-radio>
                </el-radio-group>
            </el-form-item>
            <menusOperateCatalogue :form="form" :billState="billState" v-show="form.type==1"/>
            <menusOperateMenu :form="form" :billState="billState" v-show="form.type==2"/>
            <menusOperateButton :form="form" :billState="billState" v-show="form.type==3"/>
        </el-form>
        <template #footer>
            <span>
                <el-button type="primary" class="" v-if="dialogState == 'add'" :loading="submitLoading" @click="submitClick">确定</el-button>
                <el-button type="primary" class="" v-if="dialogState == 'update'" :loading="updateLoading" @click="updateClick">确定</el-button>
                <el-button class="" @click="resetForm(formRef)">关闭</el-button>
            </span>
        </template>
    </el-dialog>
</template>

<script setup>
import { reactive, ref } from 'vue';
import { ElMessage } from 'element-plus';

import MenusTree from '@/components/system/menus-tree.vue';
import menusOperateCatalogue from './menus-operate-catalogue.vue';
import menusOperateMenu from './menus-operate-menu.vue';
import menusOperateButton from './menus-operate-button.vue';

import { menusApi } from '@/api/system/menus/menus-api';

import { deepClone, setTreeData } from '@/utils/tools-util';

// ========================= 实列挂载之前调用 =========================
let initForm = reactive({});
onBeforeMount(() => {
    // 初始化表单
    initForm = deepClone(form);
})


// ========================= 弹框控制 =========================
let dialogVisible = ref(false);
let dialogState = ref('add');
// 打开弹框
const onShowDialog = (type, row) => {
    dialogState.value = type;
    getTableData((data) => {
        if(row) {
            if(dialogState.value == 'add') {
                form.parentId = row.id;
                parentTitle.value = row.title;
            };
            if(dialogState.value == 'update' || dialogState.value == 'view') {
                for(let key in form) {
                    form[key] = row[key];
                };
                for(let item of data) {
                    if(row.parentId == 0) {
                        parentTitle.value = '主类目';
                        break;
                    };
                    if(item.id == row.parentId) {
                        parentTitle.value = item.title;
                    };
                }
            };
        }
    });
    dialogVisible.value = true;
};

// 计算属性
const typeTitle = computed(() => {
    if(dialogState.value == 'add') return '新增';
    if(dialogState.value == 'update') return '修改';
    if(dialogState.value == 'view') return '查看';
});

const billState = computed(() => {
    if(dialogState.value != 'view') return false;
    return true;
})

// 组件向外暴露属性或方法
defineExpose({
    onShowDialog
});

// ========================= 上级菜单 =========================
let menuList = ref([]);
async function getTableData (cb) {
    const res = await menusApi.list();
    let data = res.data.data;
    menuList.value = setTreeData(data, 'id', 'parentId', 'children');
    cb(data);
};

// 控制可见
const menusVisible = ref(false);
function onMenuclick() {
    if(billState.value) return false;
    menusVisible.value = !menusVisible.value;
};

// 节点点击
let parentTitle = ref('主类目');
function nodeClick(data) {
    form.parentId = data.id;
    parentTitle.value = data.title;
    onMenuclick();
};


// ========================= 表单 =========================
let form = reactive({
    id:0,                      // 键值
    parentId:0,                // 父级id
    type:1,                     // 菜单类别
    path:'',                    // 菜单路径
    component:'',               // 菜单地址
    title:'',                   // 菜单标题
    perms:'',                   // 权限标识
    icon:'',                    // 菜单图标
    sort:'',                    // 显示排序
    state: true,                // 菜单状态
    showState: true,            // 显示状态
    cache: true,                // 是否缓存
    externalLink:false,         // 是否外链
    createAt:'',                // 创建时间
    updateAt:'',                // 更新时间
});
// 菜单路径校验
const pathValidator = (rule, value, callback) => {
    if(value === ''&&form.type !== 3) {
        callback(new Error('菜单路径不能为空'));
    };
    callback();
};
const rules = reactive({
    title: [
        { required: true, message: '菜单标题不能为空', trigger: 'change' }
    ],
    path: [
        {required: true, validator: pathValidator, trigger: 'change'},
    ],
    sort: [
        { required: true, message: '菜单顺序不能为空', trigger: 'change' }
    ],
});

// 提交表单 
const formRef = ref();
let submitLoading = ref(false);
function submitClick() {
    formRef.value.validate(async (valid) => {
        try {
            if(valid) {
                submitLoading.value = true;
                let date = new Date();
                setTypeData(form.type);
                form.createAt = date;
                form.updateAt = date;
                const res = await menusApi.create(form);
                if(res.meta.status !== 200) throw new Error(res.meta.msg);
                ElMessage.success('新增成功');
                submitLoading.value = false;
                dialogVisible.value = false;
                emits('updateMenusList');
            };
        } catch (e) {
            console.error(e);
            ElMessage.error(e.message);
        } finally {
            submitLoading.value = false;
        };
    })
};
// 设置类型数据
function setTypeData(type) {
    if(type == 1) {
        form.component = initForm.component;
        form.cache = initForm.cache;
    };
    if(type == 3) {
        for(let key in form) {
            if(key == 'title' || key == 'sort' || 
            key == 'type'|| key == 'parentId'|| 
            key == 'id'|| key == 'perms' || key == 'icon') continue;
            form[key] = initForm[key];
        }
    };
};

// 更新提交
let updateLoading = ref(false);
function updateClick() {
    formRef.value.validate(async (valid) => {
        try {
            if(valid) {
                updateLoading.value = true;
                let date = new Date();
                setTypeData(form.type);
                form.updateAt = date;
                const res = await menusApi.update(form);
                if(res.meta.status !== 200) throw new Error(res.meta.msg);
                ElMessage.success('修改成功');
                dialogVisible.value = false;
                updateLoading.value = false;
                emits('updateMenusList');
            };
        } catch (e) {
            console.error(e);
            ElMessage.error(e.message);
        } finally {
            updateLoading.value = false;
        };
    });
};

// ========================= 定义发射给父组件的方法 =========================
const emits = defineEmits(['updateMenusList']);

// 重置表单 
function resetForm(refFormName) {
    refFormName.resetFields();
    for(let key in form) {
        form[key] = '';
    };
    form.id = 0;
    form.parentId = 0;
    form.type = 1;
    form.externalLink = false;
    form.cache = true;
    form.showState = true;
    form.state = true;
    parentTitle.value = '主类目';
    menusVisible.value = false;
    dialogVisible.value = false;
    submitLoading.value = false;
};
</script>

<style lang="scss" scoped>
.top-menus-box {
    width: 100%;
    position: relative;
    input {
        width: 100%;
        height: 32px;
        border: 1px solid #ddd;
        padding: 0 10px;
        border-radius: 2px;
    }
    .menus-tree-container {
    width: 100%;
    position: absolute;
    left: 0;
    top: 31px;
    background-color: $common-white-color;
    z-index: 10;
    border: 1px solid #ddd;
    @include border-radius-all(0,0,4px,4px);
    .icon-box {
        padding: 5px;
        i:hover {
            cursor: pointer;
            color: $button-blue-color;
        }
    }
    .tree-box{
        max-height: 200px;
        overflow-y:scroll;
    }
}
}
</style>